/*
 * Copyright 2020 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "include/core/SkColorFilter.h"
#include "include/effects/SkImageFilters.h"
#include "include/private/SkColorData.h"
#include "modules/svg/include/SkSVGAttributeParser.h"
#include "modules/svg/include/SkSVGFeColorMatrix.h"
#include "modules/svg/include/SkSVGFilterContext.h"
#include "modules/svg/include/SkSVGRenderContext.h"
#include "modules/svg/include/SkSVGValue.h"

bool SkSVGFeColorMatrix::parseAndSetAttribute(const char *name, const char *value)
{
    return INHERITED::parseAndSetAttribute(name, value) ||
        this->setType(SkSVGAttributeParser::parse<SkSVGFeColorMatrixType>("type", name, value)) ||
        this->setValues(SkSVGAttributeParser::parse<SkSVGFeColorMatrixValues>("values", name, value));
}

SkColorMatrix SkSVGFeColorMatrix::makeMatrixForType() const
{
    if (fValues.empty() && fType != SkSVGFeColorMatrixType::kLuminanceToAlpha) {
        return SkColorMatrix();
    }

    switch (fType) {
        case SkSVGFeColorMatrixType::kMatrix: {
            if (fValues.size() < 20) {
                return SkColorMatrix();
            }
            SkColorMatrix m;
            m.setRowMajor(fValues.data());
            return m;
        }
        case SkSVGFeColorMatrixType::kSaturate:
            return MakeSaturate(!fValues.empty() ? fValues[0] : 1);
        case SkSVGFeColorMatrixType::kHueRotate:
            return MakeHueRotate(!fValues.empty() ? fValues[0] : 0);
        case SkSVGFeColorMatrixType::kLuminanceToAlpha:
            return MakeLuminanceToAlpha();
    }

    SkUNREACHABLE;
}

SkColorMatrix SkSVGFeColorMatrix::MakeSaturate(SkSVGNumberType s)
{
    SkColorMatrix m;
    m.setSaturation(s);
    return m;
}

SkColorMatrix SkSVGFeColorMatrix::MakeHueRotate(SkSVGNumberType degrees)
{
    const SkScalar theta = SkDegreesToRadians(degrees);
    const SkSVGNumberType c = SkScalarCos(theta);
    const SkSVGNumberType s = SkScalarSin(theta);
    return SkColorMatrix(0.213f + c * 0.787f + s * -0.213f, 0.715f + c * -0.715f + s * -0.715f,
        0.072f + c * -0.072f + s * 0.928f, 0, 0,

        0.213f + c * -0.213f + s * 0.143f, 0.715f + c * 0.285f + s * 0.140f, 0.072f + c * -0.072f + s * -0.283f, 0, 0,

        0.213f + c * -0.213f + s * -0.787f, 0.715f + c * -0.715f + s * 0.715f, 0.072f + c * 0.928f + s * 0.072f, 0, 0,

        0, 0, 0, 1, 0);
}

SkColorMatrix SkSVGFeColorMatrix::MakeLuminanceToAlpha()
{
    return SkColorMatrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, SK_LUM_COEFF_R, SK_LUM_COEFF_G, SK_LUM_COEFF_B, 0,
        0);
}

sk_sp<SkImageFilter> SkSVGFeColorMatrix::onMakeImageFilter(const SkSVGRenderContext &ctx,
    const SkSVGFilterContext &fctx) const
{
    return SkImageFilters::ColorFilter(SkColorFilters::Matrix(makeMatrixForType()),
        fctx.resolveInput(ctx, this->getIn(), this->resolveColorspace(ctx, fctx)),
        this->resolveFilterSubregion(ctx, fctx));
}

template <> bool SkSVGAttributeParser::parse(SkSVGFeColorMatrixType *type)
{
    static constexpr std::tuple<const char*, SkSVGFeColorMatrixType> gTypeMap[] = {
            {"matrix", SkSVGFeColorMatrixType::kMatrix},
            {"saturate", SkSVGFeColorMatrixType::kSaturate},
            {"hueRotate", SkSVGFeColorMatrixType::kHueRotate},
            {"luminanceToAlpha", SkSVGFeColorMatrixType::kLuminanceToAlpha},
    };

    return this->parseEnumMap(gTypeMap, type) && this->parseEOSToken();
}
